import { openDB } from 'idb'
import { sendFileDataChangeToMainDebounceFn } from '../utils/file'

export const INDEXEDDB_BOARD_FILE_KEY = 'board'
export const INDEXEDDB_REVEZONE_BOARD = 'revezone_board'

const EXCALIDRAW_INITIAL_DATA = {
  elements: []
}

class BoardIndexeddbStorage {
  constructor() {
    if (BoardIndexeddbStorage.instance) {
      return BoardIndexeddbStorage.instance
    }

    BoardIndexeddbStorage.instance = this
    ;(async () => {
      this.db = await this.initDB()
    })()
  }

  static instance

  db

  async initDB() {
    if (this.db) {
      return this.db
    }

    const db = await openDB(INDEXEDDB_REVEZONE_BOARD, 1, {
      upgrade: async (db) => {
        await this.initBoardFileStore(db)
      }
    })

    this.db = db

    return db
  }

  async initBoardFileStore(db) {
    const boardStore = await db.createObjectStore(INDEXEDDB_BOARD_FILE_KEY, {
      autoIncrement: true
    })

    return boardStore
  }

  async updateBoard(id, boardData, fileTree) {
    await this.initDB()

    const isExisted = !!(await this.db?.get(INDEXEDDB_BOARD_FILE_KEY, id))

    if (!isExisted) {
      console.warn(`Board ${id} not existed, cannot update!`)
      return
    }

    await this.db?.put(INDEXEDDB_BOARD_FILE_KEY, boardData, id)

    sendFileDataChangeToMainDebounceFn(id, JSON.stringify(boardData), fileTree)
  }

  async addBoard(id, boardData = EXCALIDRAW_INITIAL_DATA) {
    await this.initDB()
    await this.db?.add(INDEXEDDB_BOARD_FILE_KEY, boardData, id)
  }

  async getBoard(id) {
    await this.initDB()
    return await this.db?.get(INDEXEDDB_BOARD_FILE_KEY, id)
  }

  async getAllBoardIds() {
    await this.initDB()
    return (await this.db?.getAllKeys(INDEXEDDB_BOARD_FILE_KEY)) || []
  }

  async deleteBoard(id) {
    await this.initDB()

    await this.db?.delete(INDEXEDDB_BOARD_FILE_KEY, id)
  }
}

export const boardIndexeddbStorage = new BoardIndexeddbStorage()
